use crate::{
    database::{DataSource, DatabaseType},
    datasource::{QueryCondition, RelationCondition},
    error::Error,
};
use derive_builder::Builder;
use serde::{Deserialize, Serialize};

use super::{
    Class, ClassPersistence, ClassRelation, DataSourceClassRelationMapping, Relation, Value,
};

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "QueryConditionByClassOptionsBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct QueryConditionByClassOptions {
    pub depth: Option<i32>,
}

#[async_trait::async_trait]
pub trait MetaConnector {
    //
    async fn get_class(&self, class_identifier: &String) -> anyhow::Result<Class>;

    async fn get_relation(&self, relation_identifier: &String) -> anyhow::Result<Relation>;
    /// 通过领域获取，所有的类
    async fn domain_classes(&self, domain_identifier: &String) -> anyhow::Result<Vec<Class>>;

    async fn get_class_persistence(
        &self,
        class_identifier: &String,
    ) -> anyhow::Result<ClassPersistence>;

    async fn query_condition_by_class_object(
        &self,
        src_class_identifier: &String,
        target_class_identifier: &String,
        object: &Value,
        relation_conditions: &Option<RelationCondition>,
        options: QueryConditionByClassOptions,
    ) -> anyhow::Result<QueryCondition>;

    async fn class_relations(
        &self,
        class_identifier: &String,
        condition: &RelationCondition,
    ) -> anyhow::Result<Vec<ClassRelation>>;

    async fn relation_mapping(
        &self,
        class_identifier: &String,
        condition: &RelationCondition,
    ) -> anyhow::Result<Vec<DataSourceClassRelationMapping>>;

    async fn generate_sql(
        &self,
        domain_identifier: &String,
        database_type: DatabaseType,
    ) -> anyhow::Result<Vec<String>>;

    async fn domain_download(
        &self,
        domain_identifier: &String,
        shared_object_id: &String,
    ) -> anyhow::Result<i32> {
        //TODO 获取TOKEN

        //下载

        //调用存储domain

        Err(anyhow::anyhow!(""))
    }
}

#[async_trait::async_trait]
pub trait ModelingSqlGenerator {
    /// 类型的DDL
    async fn class_struct_sql(
        &self,
        meta_datasource: &DataSource,
        class: Class,
        persistence: ClassPersistence,
    ) -> anyhow::Result<String>;
}
